#pragma once
#include <iostream>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <functional>
#include <unistd.h>
#include <thread>
#include "InterAddr.hpp"

const int default_backlog = 4;
using func_t = std::function<std::string(const std::string &, InterAddr &)>;
using task_t = std::function<void()>;

namespace SocketServer
{
    /*
        基类的Socket提供TCP/UDP对应的接口函数
        TCP/UDP类继承Socket, 重写所需要的虚函数
        UDP: socket + bind + recvfrom + sendto
        TCP: socket + bind + listen + accept
        使用基类指针指向子类对象实现
    */

    class Socket
    {
    public:
        Socket()
            : _socketfd(-1)
        {
        }
        // 创建对应的socket
        virtual void CreateSocket() = 0;
        virtual void CreateBind() = 0;
        virtual void Listen() = 0;
        virtual int Accept(InterAddr &peer) = 0;
        virtual void Server(const int sockfd, const InterAddr &peer) = 0;
        void UDPServerMethod();
        void TCPServerMethod()
        {
            // Init
            CreateSocket();
            CreateBind();
            Listen();

            // Run
            while (true)
            {
                InterAddr peeraddr;
                _socketfd = Accept(peeraddr);
                if (_socketfd < 0)
                    continue;
                
                // 分离线程处理
                std::thread connThread([this, peeraddr](){
                    this->Server(_socketfd, peeraddr);
                    close(_socketfd);
                });
                connThread.detach();
            }
        }

        virtual ~Socket() {
            if(_socketfd >= 0) close(_socketfd);
        }

    protected:
        int _socketfd; /* 套接字 */
        InterAddr _local_addr;
    };

    class TCPServer : public Socket
    {
    public:
        using ptr = std::unique_ptr<TCPServer>;
        TCPServer(u_int16_t port)
            : _port(port)
        {
        }

        virtual void CreateSocket() override
        {
            _ListenSocket = socket(AF_INET, SOCK_STREAM, 0);
            if (_ListenSocket < 0)
            {
                std::cout << "_ListenSocket error!" << std::endl;
                exit(-1);
            }
        }

        virtual void CreateBind() override
        {
            _local_addr = InterAddr(_port);
            int n = bind(_ListenSocket, (const sockaddr *)&_local_addr.Get_addr(), _local_addr.Get_Len());
            if (n < 0)
            {
                std::cout << "TCPServer bind error!" << std::endl;
                close(_ListenSocket);
                exit(-1);
            }
        }

        virtual void Listen() override
        {
            int n = listen(_ListenSocket, default_backlog);
            if (n < 0)
            {
                std::cout << "TCPServer listen error!" << std::endl;
                close(_ListenSocket);
                exit(-1);
            }
        }

        virtual int Accept(InterAddr& peer) override
        {
            socklen_t len = peer.Get_Len();
            int sockfd = accept(_ListenSocket, (sockaddr *)&peer.Get_addr(), &len);
            if(sockfd > 0) 
                std::cout << peer.Name() << " 建立链接" << std::endl;
            return sockfd;
        }

        virtual void Server(const int sockfd, const InterAddr& peer) override
        {
            while (true)
            {
                /* 1. 读取来自Client端的消息 */
                //     a. n > 0: 读取成功
                //     b. n < 0: 读取失败
                //     c. n == 0: Client端把链接关闭了，读到了文件的结尾
                char buffer[1024];
                int n = read(sockfd, buffer, sizeof(buffer) - 1);
                if (n > 0)
                {
                    buffer[n] = 0;
                    // 解析读取到的消息, 将解析的消息使用传入的回调函数处理, 将消息转发回client
                    // TODO
                    // for_test
                    std::cout << "[" << peer.Get_IP() << ":" << peer.Get_Port()
                              << "]: " << buffer << std::endl;
                    std::string test = "OK";
                    write(sockfd, test.c_str(), test.size());
                }
                else if (n == 0)
                {
                    std::cout << "正常退出" << std::endl;
                    break;
                }
                else if (n < 0)
                {
                    perror("异常了: \n");
                    break;
                }
            }
        }

    private:
        u_int16_t _port;   /* 端口号 */
        int _ListenSocket; /* 监听套接字 */
    };

}